package cn.iocoder.yudao.module.system.dal.mysql.examclass;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.examclass.vo.ExamClassStudentPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.examclass.ExamClassStudentDO;
import org.apache.ibatis.annotations.Mapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 班级学生关联 Mapper
 *
 * @author 芋道源码
 */
@Mapper
public interface ExamClassStudentMapper extends BaseMapperX<ExamClassStudentDO> {

    default PageResult<ExamClassStudentDO> selectPage(ExamClassStudentPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eqIfPresent(ExamClassStudentDO::getClassId, reqVO.getClassId())
                .eqIfPresent(ExamClassStudentDO::getStudentId, reqVO.getStudentId())
                .likeIfPresent(ExamClassStudentDO::getStudentNo, reqVO.getStudentNo())
                .likeIfPresent(ExamClassStudentDO::getStudentName, reqVO.getStudentName())
                .eqIfPresent(ExamClassStudentDO::getStatus, reqVO.getStatus())
                .betweenIfPresent(ExamClassStudentDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(ExamClassStudentDO::getId));
    }

    default List<ExamClassStudentDO> selectList(ExamClassStudentPageReqVO reqVO) {
        return selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eqIfPresent(ExamClassStudentDO::getClassId, reqVO.getClassId())
                .eqIfPresent(ExamClassStudentDO::getStudentId, reqVO.getStudentId())
                .likeIfPresent(ExamClassStudentDO::getStudentNo, reqVO.getStudentNo())
                .likeIfPresent(ExamClassStudentDO::getStudentName, reqVO.getStudentName())
                .eqIfPresent(ExamClassStudentDO::getStatus, reqVO.getStatus())
                .betweenIfPresent(ExamClassStudentDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(ExamClassStudentDO::getId));
    }

    default List<ExamClassStudentDO> selectListByClassId(Long classId) {
        return selectList(ExamClassStudentDO::getClassId, classId);
    }

    default ExamClassStudentDO selectByClassIdAndStudentId(Long classId, Long studentId) {
        return selectOne(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getClassId, classId)
                .eq(ExamClassStudentDO::getStudentId, studentId));
    }

    default ExamClassStudentDO selectByStudentNo(String studentNo) {
        return selectOne(ExamClassStudentDO::getStudentNo, studentNo);
    }

    /**
     * 根据考号查询学生
     * 
     * @param examNo 考号
     * @return 学生信息，如果不存在则返回null
     */
    default ExamClassStudentDO selectByExamNo(String examNo) {
        return selectOne(ExamClassStudentDO::getExamNo, examNo);
    }

    /**
     * 根据考号和班级名称查询学生（数据隔离优化）
     * 在多部门场景下，同时使用考号和班级名称查询更安全
     */
    default ExamClassStudentDO selectByStudentNoAndClassName(String studentNo, String className) {
        return selectOne(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getStudentNo, studentNo)
                .eq(ExamClassStudentDO::getClassName, className));
    }

    default Long selectCountByClassId(Long classId) {
        return selectCount(ExamClassStudentDO::getClassId, classId);
    }

    default List<ExamClassStudentDO> selectListByStudentId(Long studentId) {
        return selectList(ExamClassStudentDO::getStudentId, studentId);
    }

    /**
     * 根据学生姓名和班级名称查询学生列表（处理同名学生情况）
     */
    default List<ExamClassStudentDO> selectListByStudentNameAndClassName(String studentName, String className) {
        return selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getStudentName, studentName)
                .eq(ExamClassStudentDO::getClassName, className));
    }

    /**
     * 根据学生姓名和班级ID查询学生列表（推荐使用，避免不同部门同名班级的冲突）
     */
    default List<ExamClassStudentDO> selectListByStudentNameAndClassId(String studentName, Long classId) {
        return selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getStudentName, studentName)
                .eq(ExamClassStudentDO::getClassId, classId));
    }

    /**
     * 根据学生姓名和班级名称查询学生（兼容方法，处理同名学生时返回第一个）
     * @deprecated 建议使用 selectListByStudentNameAndClassName 方法处理同名学生情况
     */
    @Deprecated
    default ExamClassStudentDO selectByStudentNameAndClassName(String studentName, String className) {
        List<ExamClassStudentDO> students = selectListByStudentNameAndClassName(studentName, className);
        return students.isEmpty() ? null : students.get(0);
    }

    /**
     * 统计班级学生数量（按student_id去重，避免重复计数）
     */
    default int countByClassId(Long classId) {
        // 查询所有正常状态的学生，按student_id去重
        List<ExamClassStudentDO> students = selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getClassId, classId)
                .eq(ExamClassStudentDO::getStatus, 1)); // 只统计正常状态的学生
        
        // 按student_id去重后统计数量
        return (int) students.stream()
                .map(ExamClassStudentDO::getStudentId)
                .distinct()
                .count();
    }

    /**
     * 检查指定班级中是否存在同名学生
     */
    default List<String> findDuplicateStudentNamesInClass(String className) {
        List<ExamClassStudentDO> students = selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getClassName, className)
                .eq(ExamClassStudentDO::getStatus, 1)); // 只查询正常状态的学生
        
        Map<String, Long> nameCountMap = students.stream()
                .collect(Collectors.groupingBy(ExamClassStudentDO::getStudentName, Collectors.counting()));
        
        return nameCountMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }

    /**
     * 获取所有班级中的同名学生统计
     */
    default Map<String, List<String>> findAllDuplicateStudentNames() {
        List<ExamClassStudentDO> allStudents = selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .eq(ExamClassStudentDO::getStatus, 1)); // 只查询正常状态的学生
        
        Map<String, List<String>> result = new HashMap<>();
        
        // 按班级分组
        Map<String, List<ExamClassStudentDO>> studentsByClass = allStudents.stream()
                .collect(Collectors.groupingBy(ExamClassStudentDO::getClassName));
        
        // 检查每个班级的同名学生
        for (Map.Entry<String, List<ExamClassStudentDO>> entry : studentsByClass.entrySet()) {
            String className = entry.getKey();
            List<ExamClassStudentDO> classStudents = entry.getValue();
            
            Map<String, Long> nameCountMap = classStudents.stream()
                    .collect(Collectors.groupingBy(ExamClassStudentDO::getStudentName, Collectors.counting()));
            
            List<String> duplicateNames = nameCountMap.entrySet().stream()
                    .filter(nameEntry -> nameEntry.getValue() > 1)
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());
            
            if (!duplicateNames.isEmpty()) {
                result.put(className, duplicateNames);
            }
        }
        
        return result;
    }

    /**
     * 批量查询学生（根据学生姓名和班级名称的组合）
     * 优化性能：一次查询多个学生，避免N+1查询
     */
    default Map<String, ExamClassStudentDO> selectMapByStudentNamesAndClassNames(List<String> studentNames, List<String> classNames) {
        if (studentNames == null || studentNames.isEmpty() || classNames == null || classNames.isEmpty()) {
            return new HashMap<>();
        }
        
        List<ExamClassStudentDO> students = selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .in(ExamClassStudentDO::getStudentName, studentNames)
                .in(ExamClassStudentDO::getClassName, classNames));
        
        // 使用 studentName#className 作为key，便于快速查找
        return students.stream()
                .collect(Collectors.toMap(
                    student -> student.getStudentName() + "#" + student.getClassName(),
                    student -> student,
                    (existing, replacement) -> existing // 如果有重复，保留第一个
                ));
    }

    /**
     * 批量插入学生记录
     * 优化性能：使用批量插入替代逐条插入
     */
    default int insertBatch(List<ExamClassStudentDO> students) {
        if (students == null || students.isEmpty()) {
            return 0;
        }
        
        // 使用MyBatis-Plus的批量插入
        int totalInserted = 0;
        int batchSize = 500;
        
        for (int i = 0; i < students.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, students.size());
            List<ExamClassStudentDO> batch = students.subList(i, endIndex);
            
            // 逐个插入（在事务中会被优化）
            for (ExamClassStudentDO student : batch) {
                insert(student);
                totalInserted++;
            }
        }
        
        return totalInserted;
    }

    /**
     * 批量统计各班级的学生数量（按student_id去重，避免重复计数）
     * 优化性能：一次查询获取所有班级的学生数
     */
    default Map<Long, Integer> countStudentsByClassIds(List<Long> classIds) {
        if (classIds == null || classIds.isEmpty()) {
            return new HashMap<>();
        }
        
        List<ExamClassStudentDO> students = selectList(new LambdaQueryWrapperX<ExamClassStudentDO>()
                .in(ExamClassStudentDO::getClassId, classIds)
                .eq(ExamClassStudentDO::getStatus, 1)); // 只统计正常状态的学生
        
        // 按班级分组，并在每个班级内按student_id去重后统计数量
        return students.stream()
                .collect(Collectors.groupingBy(
                    ExamClassStudentDO::getClassId,
                    Collectors.collectingAndThen(
                        Collectors.mapping(ExamClassStudentDO::getStudentId, Collectors.toSet()),
                        set -> set.size()
                    )
                ));
    }

}